package com.autonavi.yunda.yunji.core.utils;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

@SuppressWarnings("unused")
public class SignUtils {
    public static final String SIGN_TYPE_RSA = "RSA";
    public static final String SIGN_ALGORITHMS_SHA1 = "SHA1WithRSA";
    public static final String SIGN_ALGORITHMS_SHA256 = "SHA256WithRSA";
    public static final String SIGN_ALGORITHMS_MD5 = "MD5withRSA";

    /**
     * 计算签名
     *
     * @param data           要计算签名的原始报文
     * @param charset        字符集（为空按系统默认处理）
     * @param signType       签名类型（目前仅RSA）
     * @param signAlgorithms 签名算法
     * @param signKey        签名秘钥（一般是私钥，防止数据被篡改）
     * @return 签名
     */
    public static String sign(String data, String charset, String signType, String signAlgorithms, String signKey) throws Exception {
        // 目前仅支持RSA
        if (SIGN_TYPE_RSA.equals(signType)) {
            PrivateKey privateKey = getPrivateKeyFromPkcs8(signType, signKey);
            Signature signature = Signature.getInstance(signAlgorithms);
            signature.initSign(privateKey);
            signature.update(data.getBytes(null != charset ? Charset.forName(charset) : StandardCharsets.UTF_8));
            return new String(Base64.getEncoder().encode(signature.sign()));
        }

        return null;
    }

    /**
     * 验证签名
     *
     * @param data           待验签的报文
     * @param charset        字符集
     * @param sign           待验签的签名
     * @param signType       签名类型
     * @param signAlgorithms 签名算法
     * @param signKey        签名秘钥（一般是公钥）
     * @return 验证是否通过
     */
    public static boolean verify(String data, String charset, String sign, String signType, String signAlgorithms, String signKey) throws Exception {
        // 目前仅支持RSA
        if (SIGN_TYPE_RSA.equals(signType)) {
            PublicKey publicKey = getPublicKeyFromX509(signType, signKey);
            Signature signature = Signature.getInstance(signAlgorithms);
            signature.initVerify(publicKey);
            signature.update(data.getBytes(null != charset ? Charset.forName(charset) : StandardCharsets.UTF_8));
            return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
        }

        return true;
    }

    /**
     * 读取私钥
     *
     * @param signType 算法
     * @param signKey  密钥串
     * @return 私钥
     * @throws Exception exception
     */
    public static PrivateKey getPrivateKeyFromPkcs8(String signType, String signKey) throws Exception {
        if (signKey == null || signType == null || "".equals(signType)) {
            return null;
        }

        KeyFactory keyFactory = KeyFactory.getInstance(signType);
        byte[] encodedKey = signKey.getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    /**
     * 读取公钥
     *
     * @param signType 算法
     * @param signKey  密钥串
     * @return 公钥
     * @throws Exception exception
     */
    public static PublicKey getPublicKeyFromX509(String signType, String signKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(signType);
        byte[] encodedKey = signKey.getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(1024);
        return generator.generateKeyPair();
    }
}
